#include <psp2kern/kernel/sysclib.h>
#include <psp2kern/kernel/sysmem.h>
#include <psp2kern/io/fcntl.h>
#include <psp2kern/ctrl.h>

#include "utils.h"

SceButtons sce_buttons;

void readPadEx(SceButtons *buttons, SceCtrlData *ctrl, int negative)
{
    buttons->old = buttons->current;
    buttons->current = negative ? ~ctrl->buttons : ctrl->buttons;
}

int isKeyOldEx(SceButtons *buttons, int key)
{
    return (buttons->old & key);
}

int isKeyCurrentEx(SceButtons *buttons, int key)
{
    return (buttons->current & key);
}

int isKeyPressedEx(SceButtons *buttons, int key)
{
    return ((buttons->current & key) && !(buttons->old & key));
}

int isKeyReleasedEx(SceButtons *buttons, int key)
{
    return (!(buttons->current & key) && (buttons->old & key));
}

void readPad(SceCtrlData *ctrl, int negative)
{
    return readPadEx(&sce_buttons, ctrl, negative);
}

int isKeyOld(int key)
{
    return isKeyOldEx(&sce_buttons, key);
}

int isKeyCurrent(int key)
{
    return isKeyCurrentEx(&sce_buttons, key);
}

int isKeyPressed(int key)
{
    return isKeyPressedEx(&sce_buttons, key);
}

int isKeyReleased(int key)
{
    return isKeyReleasedEx(&sce_buttons, key);
}

void refreshListPos(int *top_pos, int *focus_pos, int length, int lines)
{
    int temp_top_pos = *top_pos;
    int temp_focus_pos = *focus_pos;

    if (temp_focus_pos > length - 1)
        temp_focus_pos = length - 1;
    if (temp_focus_pos < 0)
        temp_focus_pos = 0;

    int lines_center = (float)lines / 2 + 0.5f;
    temp_top_pos = temp_focus_pos - lines_center + 1;

    if (temp_top_pos > length - lines)
        temp_top_pos = length - lines;
    if (temp_top_pos < 0)
        temp_top_pos = 0;

    *top_pos = temp_top_pos;
    *focus_pos = temp_focus_pos;
}

void refreshListPosNoFocus(int *top_pos, int length, int lines)
{
    int temp_top_pos = *top_pos;

    if (temp_top_pos > length - lines)
        temp_top_pos = length - lines;
    if (temp_top_pos < 0)
        temp_top_pos = 0;

    *top_pos = temp_top_pos;
}

void *SceMalloc(unsigned int size, SceUID *uid)
{
    void *mem = NULL;

    size = ALIGN(size, 4 * 1024);
    *uid = ksceKernelAllocMemBlock("kernel_rw_mem", SCE_KERNEL_MEMBLOCK_TYPE_KERNEL_RW, size, NULL);

    if (*uid < 0)
        return NULL;

    if (ksceKernelGetMemBlockBase(*uid, &mem) < 0)
        return NULL;

    return mem;
}

void SceFree(SceUID uid)
{
    ksceKernelFreeMemBlock(uid);
}

int ReadFile(const char *file, void *buffer, int size)
{
    SceUID fd = ksceIoOpen(file, SCE_O_RDONLY, 0);
    if (fd < 0)
        return fd;

    int read = ksceIoRead(fd, buffer, size);
    ksceIoClose(fd);

    return read;
}

int WriteFile(const char *file, const void *buffer, int size)
{
    SceUID fd = ksceIoOpen(file, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
    if (fd < 0)
        return fd;

    int written = ksceIoWrite(fd, buffer, size);

    ksceIoClose(fd);
    return written;
}

void getSizeString(char string[16], uint64_t size)
{
    int i = 0;
    static char *units[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
    while (size >= 1024)
    {
        size /= 1024;
        i++;
    }

    snprintf(string, 16, "%llu%s", size, units[i]);
}
